#include "stdafx.h"
#include <stack>
#include "PPProjTreeImp.h"
#include "utilityString.h"
#include "IteratorTool.h"
#include "PPProjTreeReadWriteHelper.h"

namespace LBPROJ
{
    CProjectTreeNode::CProjectTreeNode()
    {

    }

    CProjectTreeNode::~CProjectTreeNode()
    {

    }

    const std::wstring& CProjectTreeNode::GetID() const
    {
        if (m_id.empty())
        {
            m_id = GenerateUUID();
        }
        return m_id;
    }

    void CProjectTreeNode::SetID(const std::wstring& id)
    {
        m_id = id;
    }

    const std::wstring& CProjectTreeNode::GetName() const
    {
        return m_name;
    }

    void CProjectTreeNode::SetName(const std::wstring& name)
    {
        m_name = name;
    }

    CRefPtr<IPPContext> CProjectTreeNode::GetContext() const
    {
        return m_pContext;
    }

    void CProjectTreeNode::SetContext(const CRefPtr<IPPContext>& pContext)
    {
        m_pContext = pContext;
    }

    CRefPtr<IProjectTreeNode> CProjectTreeNode::GetParent() const
    {
        return m_pParent.Lock();
    }

    void CProjectTreeNode::SetParent(const CRefPtr<IProjectTreeNode>& pParent)
    {
        m_pParent = pParent;
    }


    void CProjectTreeNode::AddItem(const CRefPtr<IProjectTreeNode>& pItem, const CRefPtr<IProjectTreeNode>& pPos)
    {
        pItem->SetParent(this);
        if (pPos == nullptr || m_childList.empty())
        {
            m_childList.push_back(pItem);
        }
        else
        {
            auto iter = std::find(m_childList.cbegin(), m_childList.cend(), pPos);
            m_childList.insert(iter, pItem);
        }

    }

    void CProjectTreeNode::DelItem(const CRefPtr<IProjectTreeNode>& pItem)
    {
        if (!m_childList.empty())
        {
            auto iter = std::find(m_childList.cbegin(), m_childList.cend(), pItem);
            if (iter != m_childList.cend())
            {
                pItem->SetParent(nullptr);
                m_childList.erase(iter);
            }
        }
    }

    void CProjectTreeNode::DelAllItem()
    {
        for (auto iter = m_childList.begin(); iter != m_childList.end(); ++iter)
        {
            (*iter)->SetParent(nullptr);
        }
        m_childList.clear();
    }

    CRefPtr<Iterator<IProjectTreeNode*>> CProjectTreeNode::CreateIterator(bool reversed) const
    {
        return new CIteratorTool<IProjectTreeNode>(m_childList, reversed);
    }

    bool CProjectTreeNode::Store(Data & data) const
    {
        data.id = GetID();
        data.name = GetName();
        if(m_pContext != nullptr)
            data.contextId = m_pContext->GetID();
        if (GetParent() != nullptr)
            data.parentId = GetParent()->GetID();
        return true;
    }

    //////////////////////////////////////////////////////////////////////////
    //////////////////////////////////////////////////////////////////////////
    //////////////////////////////////////////////////////////////////////////
    CProjectTree::CProjectTree()
        : m_pRoot(new CProjectTreeNode())
    {

    }

    CProjectTree::~CProjectTree()
    {

    }

    CRefPtr<IProjectTreeNode> CProjectTree::GetRoot() const
    {
        return m_pRoot;
    }

    CRefPtr<IProjectTreeNode> CProjectTree::FindNodeBySequence(int sequence) const
    {
        if (sequence > 0)
        {
            std::stack<IProjectTreeNode*> nodeStack;
            nodeStack.push(GetRoot());
            int num = 0;
            while (!nodeStack.empty())
            {
                IProjectTreeNode* pCurNode = nodeStack.top();
                nodeStack.pop();
                if (num == sequence)
                    return pCurNode;
                num++;

                auto iter = pCurNode->CreateIterator(true);
                for (iter->First(); !iter->IsDone(); iter->Next())
                {
                    nodeStack.push(iter->GetCurrentItem());
                }
            }
        }
        return nullptr;
    }

    CRefPtr<IProjectTreeNode> CProjectTree::FindNodeByID(const std::wstring& id) const
    {
        if (!id.empty())
        {
            std::stack<IProjectTreeNode*> nodeStack;
            nodeStack.push(GetRoot());
            int num = 0;
            while (!nodeStack.empty())
            {
                IProjectTreeNode* pCurNode = nodeStack.top();
                nodeStack.pop();
                if (pCurNode != nullptr && pCurNode->GetID() == id)
                    return pCurNode;
                num++;

                auto iter = pCurNode->CreateIterator(true);
                for (iter->First(); !iter->IsDone(); iter->Next())
                {
                    nodeStack.push(iter->GetCurrentItem());
                }
            }
        }
        return nullptr;
    }

    bool CProjectTree::Open(LBPROJSTREAM::IProjPlanStreamDatabase* pDb)
    {
        CPPProjTreeReadWriteHelper helper(this);
        return helper.Open(pDb);
    }

    bool CProjectTree::Write(LBPROJSTREAM::IProjPlanStreamDatabase* pDb) const
    {
        CPPProjTreeReadWriteHelper helper((CProjectTree*)this);
        return helper.Write(pDb);
    }

    CRefPtr<IProjectTree> CreateProjectTree()
    {
        return new CProjectTree;
    }

    CRefPtr<IProjectTreeNode> CreateProjectTreeNode(const CRefPtr<IPPContext>& pContext)
    {
        CProjectTreeNode* pNode = new CProjectTreeNode;
        pNode->SetContext(pContext);
        return pNode;
    }
}
